Custom Visual 1.0 Example
function MyCustomVisual() {
// this function will be called before rendering the next batch of visual chunks
this.onBeforeRender = function (api) {
};
// this function should return array of strings, each string
// represent a path of a library you want to import
this.importPaths = function () {
};
//This function should render single chunk visual
this.renderChunk = function (element, chunkData, api) {
var margin = 20;
var categoriesWidth = 80;
// In the next two lines we're calling the api size section in order to get the screen height and width
var height = api.size.height - margin * 2;
var width = api.size.width - margin * 2;
// Get the d3 library in order to perform dom manipulations and paint the heat-map
var d3 = api.deps.d3;
// Get the list of the drop zones types (e.g. Columns, Rows, Values, Size etc...)
var dropZones = api.data.dropZones;
// Using the groupBy method in order to get the data points for the Columns and the Rows
var colsData = api.data.groupBy(chunkData, dropZones.Columns);
var rowsData = api.data.groupBy(chunkData, dropZones.Rows);
var colsLength = Object.keys(colsData).length;
var rowsLength = Object.keys(rowsData).length;
var itemSizeWidth = (width - categoriesWidth) / colsLength;
var cellSizeWidth = itemSizeWidth - 1;
var itemSizeHeight = (height - categoriesWidth) / rowsLength;
var cellSizeHeight = itemSizeHeight - 1;
var xScale = d3.scale.scaleBand()
.domain(Object.keys(colsData))
.range([0, width - categoriesWidth]);
var yScale = d3.scale.scaleBand()
.domain(Object.keys(rowsData))
.range([0, height - categoriesWidth]);
var xAxis = d3.axis.axisTop(xScale);
var yAxis = d3.axis.axisLeft(yScale);
// y-axis paint section
var yAxisSelection = d3.selection.select(element).selectAll('g.y-axis').data([null]);
yAxisSelection.exit().remove();
yAxisSelection = yAxisSelection
.enter()
.append('g')
.attr('class', 'y-axis')
.attr('transform', 'translate(95,100)')
.merge(yAxisSelection)
.call(yAxis);
// x-axis
var xAxisSelection = d3.selection.select(element).selectAll('g.x-axis').data([null]);
xAxisSelection.exit().remove();
xAxisSelection = xAxisSelection
.enter()
.append('g')
.attr('class', 'x-axis')
.attr('transform', 'translate(100, 95)')
.merge(xAxisSelection)
.call(xAxis)
.selectAll('text')
.attr("x", 8)
.attr("y", -2)
.attr("transform", "rotate(-65)")
.style("text-anchor", "start");
// Get heat map data
var fullData = [];
Object.keys(colsData).forEach(function (colData, i) {
var colDataPoints = colsData[colData].dataPoints;
colDataPoints.forEach(function (dp, j) {
// In the next two lines we are using the datapoints we got earlier from the "groupBy" method
// in order to get the columns and rows name.
var colName = api.data.getDataPointDropZoneCaption(dp, dropZones.Columns);
var rowName = api.data.getDataPointDropZoneCaption(dp, dropZones.Rows);
// Using the dataPoint we got earlier to get the specific cell value
var value = api.data.getDataPointValue(dp);
fullData.push({
x: i,
y: j,
dataPoint: dp,
colName: colName,
rowName: rowName,
value: value
});
});
});
// Data Heat Map
var groupSelection = d3.selection.select(element).selectAll('g.data').data([null]);
groupSelection.exit().remove();
groupSelection = groupSelection
.enter()
.append('g')
.attr('class', 'data')
.attr('transform', 'translate(100,100)')
.merge(groupSelection);
var rectSelection = d3.selection.select(element).select('g.data').selectAll('rect').data(fullData);
rectSelection.exit().remove();
rectSelection = rectSelection
.enter()
.append('rect')
.merge(rectSelection)
.attr('width', cellSizeWidth)
.attr('height', cellSizeHeight)
.attr('x', function (d) {
return d.x * itemSizeWidth;
})
.attr('y', function (d) {
return d.y * itemSizeHeight;
})
.attr('fill', function (d) {
// Using getColor function with the datapoint we got earlier to get the cell color (given "black" as a default color)
return api.data.getColor(d.dataPoint, 'black');
})
.on('mouseover', function (d) {
// Using the interaction API "showTooltip" to activate the cell tooltip
api.interaction.showTooltip(d.dataPoint)
})
.on('mouseout', function (d) {
// Using the interaction API 'hideTooltip" function to deactivate the cell tooltip
api.interaction.hideTooltip()
})
.on('contextmenu', function (d) {
// Using the interaction API "showDatapointContextMenu" function to let right clicking the cell open the cell menu
api.interaction.showDatapointContextMenu(d.dataPoint, d3.selection.event);
})
.on("click", function (d) {
// Using the interaction API "selectDatapoint" function to make the cell clickable
api.interaction.selectDatapoint(d.dataPoint, d3.selection.event)
});
}
//This function will be called for each data change
this.onDataChanged = function (fullData, api) {
};
// this function will be called for every theme or style change
this.onThemeOrStyleChanged = function (api) {
};
// this function should return css string (if any) for custom style
this.getCustomStyle = function (api) {
// Using the style API in order to get the x&y axis style color
var xAxisColor = api.style.styles.visuals.visualsXAxis.color;
var yAxisColor = api.style.styles.visuals.visualsYAxis.color;
var result = '.my-class {direction:rtl;}' +
'g.x-axis text {' +
'fill: ' + xAxisColor + ';}' +
'g.x-axis path, line {' +
'stroke: ' + xAxisColor + ';}' +
'g.y-axis text {' +
'fill: ' + yAxisColor + ';}' +
'g.y-axis path, line {' +
'stroke: ' + yAxisColor + ';}';
return result;
};
this.init = function () { };
// This line will allow debugging your Custom visual in your browser debugger
//# sourceURL=MyCustomVisual.js
}